package com.wzq.upms.common.utils;


 import java.util.BitSet;
import java.util.HashMap;
   
/**
 * 地理位置信息geohash算法工具类  
 * 
 * project：pub-core
 * 
 * $Author:Jeffy Chen
 * @version $Revision:$ 
 * @Modify $Date:$
 * @create time：2014-4-26 下午11:02:47
 *
 */
 public class GeohashUtils {  
   
     private static int numbits = 6 * 5;  
     final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8',  
             '9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p',  
             'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };  
       
     final static HashMap<Character, Integer> lookup = new HashMap<Character, Integer>();  
     static {  
         int i = 0;  
         for (char c : digits)  
             lookup.put(c, i++);  
     }  
   
     public static void main(String[] args)  throws Exception{  
         System.out.println(new GeohashUtils().decode("wx4g0ec19x3d")[0]);  
         double[] d =getAround(113.930451,22.539448,200000);
         System.out.println(d[0]+" "+d[1]+" "+d[2]+" "+d[3]);     
     }  
 
     /**
      * 把geohash解码成经纬度
      * @param geohash 编码
      * @return 经纬度数据
      */
     public double[] decode(String geohash) {  
         StringBuilder buffer = new StringBuilder();  
         for (char c : geohash.toCharArray()) {  
   
             int i = lookup.get(c) + 32;  
             buffer.append( Integer.toString(i, 2).substring(1) );  
         }  
           
         BitSet lonset = new BitSet();  
         BitSet latset = new BitSet();  
           
         //even bits  
         int j =0;  
         for (int i=0; i< numbits*2;i+=2) {  
             boolean isSet = false;  
             if ( i < buffer.length() )  
               isSet = buffer.charAt(i) == '1';  
             lonset.set(j++, isSet);  
         }  
         //odd bits  
         j=0;  
         for (int i=1; i< numbits*2;i+=2) {  
             boolean isSet = false;  
             if ( i < buffer.length() )  
               isSet = buffer.charAt(i) == '1';  
             latset.set(j++, isSet);  
         }  
         double lon = decode(lonset, -180, 180);  
         double lat = decode(latset, -90, 90);  
         return new double[] {lon, lat};       
     }  
       
     /**
      * 把BitSet解码成经纬度
      * @param bs BitSet
      * @param floor 最小角度
      * @param ceiling 最大角度
      * @return double 经度或维度
      */
     private double decode(BitSet bs, double floor, double ceiling) {  
         double mid = 0;  
         for (int i=0; i<bs.length(); i++) {  
             mid = (floor + ceiling) / 2;  
             if (bs.get(i))  
                 floor = mid;  
             else  
                 ceiling = mid;  
         }  
         return mid;  
     }  
       
       
     /**
      * 经纬度编码成geohash码
      * @param lon 经度
      * @param lat 维度
      * @return String geoHash码
      */
     public static String encode(double lon,double lat) {  
         BitSet lonbits = getBits(lon, -180, 180);  
         BitSet latbits = getBits(lat, -90, 90);  
         StringBuilder buffer = new StringBuilder();  
         for (int i = 0; i < numbits; i++) {  
             buffer.append( (lonbits.get(i))?'1':'0');  
             buffer.append( (latbits.get(i))?'1':'0');  
         }  
         return base32(Long.parseLong(buffer.toString(), 2));  
     }  
   
     /**
      * 经度或维度转成BitSet
      * @param lat 经度或维度
      * @param floor 最小角度
      * @param ceiling 最大角度
      * @return
      */
     private static BitSet getBits(double lat, double floor, double ceiling) {  
         BitSet buffer = new BitSet(numbits);  
         for (int i = 0; i < numbits; i++) {  
             double mid = (floor + ceiling) / 2;  
             if (lat >= mid) {  
                 buffer.set(i);  
                 floor = mid;  
             } else {  
                 ceiling = mid;  
             }  
         }  
         return buffer;  
     }  
   
     /**
      * base32编码
      * @param i 长整形数据
      * @return String base32编码
      */
     public static String base32(long i) {  
         char[] buf = new char[65];  
         int charPos = 64;  
         boolean negative = (i < 0);  
         if (!negative)  
             i = -i;  
         while (i <= -32) {  
             buf[charPos--] = digits[(int) (-(i % 32))];  
             i /= 32;  
         }  
         buf[charPos] = digits[(int) (-i)];  
   
         if (negative)  
             buf[--charPos] = '-';  
         return new String(buf, charPos, (65 - charPos));  
     }  
     
     /**
      * 根据经纬度换算成方圆多少m经纬度范围
      * @param lon 经度
      * @param lat 维度
      * @param raidus 半径(米)
      * @return double[] 经纬度范围
      */
     public static double[] getAround(double lon, double lat, int raidus){
		Double longitude = lon;
		Double latitude = lat;

		Double degree = (24901 * 1609) / 360.0;
		double raidusMile = raidus;

		Double dpmLat = 1 / degree;
		Double radiusLat = dpmLat * raidusMile;
		Double minLat = latitude - radiusLat;
		Double maxLat = latitude + radiusLat;

		Double mpdLng = degree * Math.cos(latitude * (Math.PI / 180));
		Double dpmLng = 1 / mpdLng;
		Double radiusLng = dpmLng * raidusMile;
		Double minLng = longitude - radiusLng;
		Double maxLng = longitude + radiusLng;
		return new double[] { minLng, minLat, maxLng, maxLat };
     }
 }
